package top.xia17.plugins.fast.common.security.token.provider;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import top.xia17.plugins.fast.common.autoconfiguration.TokenProperties;
import top.xia17.plugins.fast.common.database.redis.RedisUtils;
import top.xia17.plugins.fast.common.security.base.LoginInfo;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 简单的Token提供
 * @author xia17
 * @date 2021/6/23 17:58
 */
@RequiredArgsConstructor
public class SimpleRedisTokenProvider implements TokenProvider {

    private final RedisUtils redisUtils;
    private final TokenProperties tokenProperties;



    /**
     * 使用Token来获取认证信息
     * @param token token
     * @return /
     */
    @Override
    public Authentication getAuthentication(String token) {
        Object o = redisUtils.get(tokenProperties.getRedisKeyPrefix() + token);
        if (o == null) {
            return null;
        }
        // 是否需要续期
        checkRenewal(token);
        LoginInfo authInfo = (LoginInfo) o;
        // 权限信息
        Collection<? extends GrantedAuthority> authorities =
                ObjectUtil.isNotEmpty(authInfo.getAuthoritiesStr()) ?
                        Arrays.stream(authInfo.getAuthoritiesStr().split(","))
                                .map(SimpleGrantedAuthority::new)
                                .collect(Collectors.toList()) : Collections.emptyList();
        return new UsernamePasswordAuthenticationToken(authInfo, token, authorities);
    }

    /**
     * 生成token
     * @return 返回token
     */
    @Override
    public String generateToken(LoginInfo loginInfo){
        // token = uuid + 时间戳
        return IdUtil.fastSimpleUUID() + System.currentTimeMillis();
    }

    /**
     * 生成token并存储
     * @param loginInfo /
     * @return 返回token
     */
    @Override
    public String generateTokenAndSave(LoginInfo loginInfo){
        String token = this.generateToken(loginInfo);
        this.addToken(token,loginInfo);
        return token;
    }



    /**
     * 检查Token 是否需要续期
     * @param token 需要检查的token
     */
    @Override
    public void checkRenewal(String token){
        // 判断是否续期token,计算token的过期时间
        long time = redisUtils.getExpire(tokenProperties.getRedisKeyPrefix() + token);
        Date expireDate = DateUtil.offset(new Date(), DateField.SECOND, (int) time);
        // 判断当前时间与过期时间的时间差
        long differ = expireDate.getTime()  - System.currentTimeMillis() / 1000 ;
        // 如果在续期检查的范围内，则续期
        if(differ <= tokenProperties.getDetect()){
            long renew = time + tokenProperties.getRenew();
            redisUtils.expire(tokenProperties.getRedisKeyPrefix() + token, renew, TimeUnit.SECONDS);
        }
    }

    /**
     * 保存token信息
     * @param token token
     * @param loginInfo 认证信息
     */
    @Override
    public void addToken(String token, LoginInfo loginInfo){
        String key = tokenProperties.getRedisKeyPrefix() + token;
        redisUtils.set(key,loginInfo,tokenProperties.getTokenValidity());
    }


    /**
     * 移除Token
     * @param token /
     */
    @Override
    public void removeToken(String token) {
        redisUtils.del(tokenProperties.getRedisKeyPrefix() + token);
    }

    /**
     * 更新token信息
     * @param token token
     * @param loginInfo 信息
     */
    @Override
    public void updateTokenInfo(String token, LoginInfo loginInfo) {
        this.addToken(token,loginInfo);
    }
}
